#include <iostream>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/time.h>

#define BUFSIZE 1024
int progress = 0; // 进度
int exit_flag = 1;
std::string path1 = "./1.txt";
std::string path2 = "./2.txt";

int getFileSize(const std::string &path)
{
    // 获取文件大小
    int fd;
    struct stat buf;
    fd = open(path.c_str(), O_RDONLY);
    if (fd < 0)
    {
        perror("打开文件失败");
        exit(1);
    }
    fstat(fd, &buf);
    close(fd);
    return buf.st_size;
}

void sig_alarm(int signo)
{
    kill(getppid(), SIGUSR1);
}

void printf_progress(int signo)
{
    std::cout << "进度：" << (progress * 100 / (getFileSize(path1) / BUFSIZE + 1)) << "%" << std::endl;
    return;
}

int main()
{
    pid_t pid = fork();
    if (pid < 0)
    {
        std::cout << "创建子进程失败" << std::endl;
        return 1;
    }
    else if (pid == 0)
    {
        // 子进程
        usleep(10);
        signal(SIGALRM, sig_alarm);
        ualarm(500000, 10);
        while (1)
        {
            ;
        }
        exit(EXIT_SUCCESS);
    }
    else
    {
        // 父进程
        int fd1, fd2, count;
        char buf[BUFSIZE];

        // 先要注册信号处理函数
        struct sigaction act, oldact;
        act.sa_handler = printf_progress;  // 信号处理函数
        act.sa_flags = 0;                  // 默认信号处理方式
        sigemptyset(&act.sa_mask);         // 清空信号集
        sigaction(SIGUSR1, &act, &oldact); // 注册信号处理函数

        // 拷贝文件
        fd1 = open(path1.c_str(), O_RDONLY); // 读文件
        if (fd1 < 0)
        {
            std::cout << "打开读文件失败" << std::endl;
            exit(1);
        }

        fd2 = open(path2.c_str(), O_WRONLY | O_CREAT, 0644); // 写文件,不存在则创建
        if (fd2 < 0)
        {
            std::cout << "打开写文件失败" << std::endl;
            exit(1);
        }

        while ((count = read(fd1, buf, BUFSIZE)) > 0)
        {
            progress++;             // 进度+1
            write(fd2, buf, count); // 写文件
            sleep(1);               // 暂停一秒,方便观察效果
        }
        std::cout << "文件拷贝完成" << std::endl;
        close(fd1);
        close(fd2);
        waitpid(pid, nullptr, 0);
    }
    return 0;
}